home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / info-service / www / src / WWW / Library / Implementation / HTWAIS.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-06  |  22.0 KB  |  840 lines

  1. /*    WorldWideWeb - Wide Area Informaion Server Access    HTWAIS.c
  2. **    ==================================================
  3. **
  4. **    This module allows a WWW server or client to read data from a
  5. **    remote  WAIS
  6. **  server, and provide that data to a WWW client in hypertext form.
  7. **  Source files, once retrieved, are stored and used to provide
  8. **  information about the index when that is acessed.
  9. **
  10. ** Authors
  11. **    BK    Brewster Kahle, Thinking Machines, <Brewster@think.com>
  12. **    TBL    Tim Berners-Lee, CERN <timbl@info.cern.ch>
  13. **
  14. ** History
  15. **       Sep 91    TBL adapted shell-ui.c (BK) with HTRetrieve.c from WWW.
  16. **       Feb 91    TBL Generated HTML cleaned up a bit (quotes, escaping)
  17. **                Refers to lists of sources. 
  18. **       Mar 93    TBL   Lib 2.0 compatible module made.    
  19. **
  20. ** Bugs
  21. **    Uses C stream i/o to read and write sockets, which won't work
  22. **    on VMS TCP systems.
  23. **
  24. **    Should cache connections.
  25. **
  26. **    ANSI C only as written
  27. **
  28. ** WAIS comments:
  29. **
  30. **    1.    Separate directories for different system's .o would help
  31. **    2.    Document ids are rather long!
  32. **
  33. ** WWW Address mapping convention:
  34. **
  35. **    /servername/database/type/length/document-id
  36. **
  37. **    /servername/database?word+word+word
  38. */
  39. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  40.    No guarantees or restrictions.  See the readme file for the full standard
  41.    disclaimer.
  42.  
  43.    Brewster@think.com
  44. */
  45.  
  46.  
  47. #define DIRECTORY "/cnidr.org:210/directory-of-servers"
  48. /* define DIRECTORY "/quake.think.com:210/directory-of-servers" */
  49.  
  50. #define BIG 1024    /* identifier size limit  @@@@@ */
  51.  
  52. /*            From WAIS
  53. **            ---------
  54. */
  55.  
  56. #include <ui.h>
  57.  
  58. #define MAX_MESSAGE_LEN 100000
  59. #define CHARS_PER_PAGE 10000 /* number of chars retrieved in each request */
  60.  
  61. #define WAISSEARCH_DATE "Fri Jul 19 1991"
  62.  
  63.  
  64. /*            FROM WWW
  65. **            --------
  66. */
  67. #define BUFFER_SIZE 4096    /* Arbitrary size for efficiency */
  68.  
  69. #define HEX_ESCAPE '%'
  70.  
  71. #include "HTUtils.h"
  72. #include "tcp.h"
  73. #include "HTParse.h"
  74. #include "HTAccess.h"        /* We implement a protocol */
  75. #include "HTML.h"        /* The object we will generate */
  76.  
  77. /* #include "ParseWSRC.h" */
  78.  
  79. extern int WWW_TraceFlag;    /* Control diagnostic output */
  80. extern FILE * logfile;        /* Log file output */
  81.  
  82. PRIVATE BOOL    as_gate;    /* Client is using us as gateway */
  83.  
  84. PRIVATE char    line[2048];    /* For building strings to display */
  85.                 /* Must be able to take id */
  86.  
  87.  
  88. #include "HTParse.h"
  89. #include "HTFormat.h"
  90. #include "HTTCP.h"
  91. /* #include "HTWSRC.h"    */    /* Need some bits from here */
  92.  
  93. /*        Hypertext object building machinery
  94. */
  95. #include "HTML.h"
  96.  
  97. #define PUTC(c) (*target->isa->put_character)(target, c)
  98. #define PUTS(s) (*target->isa->put_string)(target, s)
  99. #define START(e) (*target->isa->start_element)(target, e, 0, 0)
  100. #define END(e) (*target->isa->end_element)(target, e)
  101. #define END_TARGET (*target->isa->end_document)(target)
  102. #define FREE_TARGET (*target->isa->free)(target)
  103.  
  104. struct _HTStructured {
  105.     CONST HTStructuredClass *    isa;
  106.     /* ... */
  107. };
  108.  
  109. struct _HTStream {
  110.     CONST HTStreamClass *    isa;
  111.     /* ... */
  112. };
  113.  
  114.  
  115. /*                                showDiags
  116. */
  117. /* modified from Jonny G's version in ui/question.c */
  118.  
  119. void showDiags ARGS2(
  120.     HTStream *,         target,
  121.     diagnosticRecord **,     d)
  122. {
  123.   long i;
  124.  
  125.   for (i = 0; d[i] != NULL; i++) {
  126.     if (d[i]->ADDINFO != NULL) {
  127.       PUTS("Diagnostic code is ");
  128.       PUTS(d[i]->DIAG);
  129.       PUTC(' ');
  130.       PUTS(d[i]->ADDINFO);
  131.       PUTC('\n'); ;
  132.     }
  133.   }
  134. }
  135.  
  136. /*    Matrix of allowed characters in filenames
  137. **    -----------------------------------------
  138. */
  139.  
  140. PRIVATE BOOL acceptable[256];
  141. PRIVATE BOOL acceptable_inited = NO;
  142.  
  143. PRIVATE void init_acceptable NOARGS
  144. {
  145.     unsigned int i;
  146.     char * good = 
  147.       "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_$";
  148.     for(i=0; i<256; i++) acceptable[i] = NO;
  149.     for(;*good; good++) acceptable[(unsigned int)*good] = YES;
  150.     acceptable_inited = YES;
  151. }
  152.  
  153. /*    Transform file identifier into WWW address
  154. **    ------------------------------------------
  155. **
  156. **
  157. ** On exit,
  158. **    returns        nil if error
  159. **            pointer to malloced string (must be freed) if ok
  160. */
  161. char * WWW_from_archie ARGS1 (char *, file)
  162. {
  163.     char * end;
  164.     char * result;
  165.     char * colon;
  166.     for(end=file; *end > ' '; end++);    /* assumes ASCII encoding*/
  167.     result = (char *)malloc(10 + (end-file));
  168.     if (!result) return result;        /* Malloc error */
  169.     strcpy(result, "file://");
  170.     strncat(result, file, end-file);
  171.     colon = strchr(result+7, ':');    /* Expect colon after host */
  172.     if (colon) {
  173.     for(; colon[0]; colon[0]=colon[1], colon++);    /* move down */
  174.     }
  175.     return result;
  176. } /* WWW_from_archie */
  177.  
  178. /*    Transform document identifier into URL
  179. **    --------------------------------------
  180. **
  181. ** Bugs: A static buffer of finite size is used!
  182. **    The format of the docid MUST be good!
  183. **
  184. ** On exit,
  185. **    returns        nil if error
  186. **            pointer to malloced string (must be freed) if ok
  187. */
  188. PRIVATE char hex [16] = "0123456789ABCDEF";
  189. extern char from_hex PARAMS((char a));            /* In HTWSRC @@ */
  190.  
  191. PRIVATE char * WWW_from_WAIS ARGS1(any *, docid)
  192.  
  193. {
  194.     static char buf[BIG];
  195.     char * q = buf;
  196.     char * p = (docid->bytes);
  197.     int i, l;
  198.     if (TRACE) {
  199.     char *p;
  200.     fprintf(stderr, "WAIS id (%d bytes) is ", (int)docid->size);
  201.     for(p=docid->bytes; p<docid->bytes+docid->size; p++) {
  202.         if ((*p >= ' ') && (*p<= '~')) /* Assume ASCII! */
  203.         fprintf(stderr, "%c", *p);
  204.         else
  205.         fprintf(stderr, "<%x>", (unsigned)*p);
  206.     }
  207.     fprintf(stderr, "\n");
  208.     }     
  209.     for (p=docid->bytes; (p<docid->bytes+docid->size) && (q<&buf[BIG]);) {
  210.     if (TRACE) fprintf(stderr, "    Record type %d, length %d\n",
  211.         p[0], p[1]);
  212.         if (*p>10) {
  213.         fprintf(stderr, "Eh? DOCID record type of %d!\n", *p);
  214.         return 0;
  215.     }
  216.     {    /* Bug fix -- allow any byte value 15 Apr 93 */
  217.         unsigned int i = (unsigned) *p++;
  218.         
  219.         if (i > 99) {
  220.         *q++ = (i/100) + '0';
  221.         i = i % 100;
  222.         }
  223.         if (i > 9) {
  224.         *q++ = (i/10) + '0';
  225.         i = i % 10;
  226.         }
  227.         *q++ = i + '0';    /* Record type */
  228.     }
  229.     *q++ = '=';        /* Separate */
  230.     l = *p++;        /* Length */
  231.     for(i=0; i<l; i++, p++){
  232.         if (!acceptable[*p]) {
  233.         *q++ = HEX_ESCAPE;    /* Means hex commming */
  234.         *q++ = hex[(*p) >> 4];
  235.         *q++ = hex[(*p) & 15];
  236.         }
  237.         else *q++ = *p;
  238.     }
  239.     *q++= ';';        /* Terminate field */
  240.     }
  241.     *q++ = 0;            /* Terminate string */
  242.     if (TRACE) fprintf(stderr, "WWW form of id: %s\n", buf); 
  243.     {
  244.         char * result = (char *)malloc(strlen(buf)+1);
  245.     strcpy(result, buf);
  246.     return result;
  247.     }
  248. } /* WWW_from_WAIS */
  249.  
  250.  
  251. /*    Transform URL into WAIS document identifier
  252. **    -------------------------------------------
  253. **
  254. ** On entry,
  255. **    docname        points to valid name produced originally by
  256. **            WWW_from_WAIS
  257. ** On exit,
  258. **    docid->size    is valid
  259. **    docid->bytes    is malloced and must later be freed.
  260. */
  261. PRIVATE any * WAIS_from_WWW ARGS2 (any *, docid, char *, docname)
  262. {
  263.     char *z;     /* Output pointer */
  264.     char *sor;    /* Start of record - points to size field. */
  265.     char *p;     /* Input pointer */
  266.     char *q;     /* Poisition of "=" */
  267.     char *s;     /* Position of semicolon */
  268.     int n;    /* size */
  269.     if (TRACE) fprintf(stderr, "WWW id (to become WAIS id): %s\n", docname); 
  270.     for(n=0, p = docname; *p; p++) {    /* Count sizes of strings */
  271.         n++;
  272.     if (*p == ';')  n--;        /* Not converted */
  273.     else if (*p == HEX_ESCAPE) n=n-2;    /* Save two bytes */
  274.         docid->size = n;
  275.     }
  276.     
  277.     docid->bytes = (char *) malloc(docid->size); /* result record */
  278.     z = docid->bytes;
  279.     
  280.     for(p = docname; *p; ) {    /* Convert of strings */
  281.                     /* Record type */
  282.                 
  283.     *z = 0;            /* Initialize record type */
  284.     while (*p >= '0' && *p <= '9') {
  285.         *z = *z*10 + (*p++ - '0');    /* Decode decimal record type */
  286.     }
  287.     z++;
  288.     if (*p != '=') return 0;
  289.     q = p;
  290.     
  291. /*        *z++ = *p++ - '0';
  292.     q = strchr(p , '=');
  293.     if (!q) return 0;
  294. */
  295.     s = strchr(q, ';');    /* (Check only) */
  296.     if (!s) return 0;    /* Bad! No ';';    */
  297.         sor = z;        /* Remember where the size field was */
  298.     z++;            /* Skip record size for now    */
  299.     for(p=q+1; *p!=';' ; ) {
  300.        if (*p == HEX_ESCAPE) {
  301.             char c;
  302.         unsigned int b;
  303.         p++;
  304.             c = *p++;
  305.         b =   from_hex(c);
  306.         c = *p++;
  307.         if (!c) break;    /* Odd number of chars! */
  308.         *z++ = (b<<4) + from_hex(c);
  309.         } else {
  310.             *z++ = *p++;    /* Record */
  311.         }
  312.     }
  313.     *sor = (z-sor-1);    /* Fill in size -- not counting size itself */
  314.     p++;            /* After semicolon: start of next record */
  315.     }
  316.     
  317.     if (TRACE) {
  318.     char *p;
  319.     fprintf(stderr, "WAIS id (%d bytes) is ", (int)docid->size);
  320.     for(p=docid->bytes; p<docid->bytes+docid->size; p++) {
  321.         if ((*p >= ' ') && (*p<= '~')) /* Assume ASCII! */
  322.         fprintf(stderr, "%c", *p);
  323.         else
  324.         fprintf(stderr, "<%x>", (unsigned)*p);
  325.     }
  326.     fprintf(stderr, "\n");
  327.     }     
  328.     return docid;        /* Ok */
  329.     
  330. } /* WAIS_from_WWW */
  331.  
  332.  
  333. /*    Send a plain text record to the client        output_text_record()
  334. **    --------------------------------------
  335. */
  336.  
  337. PRIVATE void output_text_record ARGS3(
  338.     HTStream *,            target,
  339.     WAISDocumentText *,        record,
  340.     boolean,            quote_string_quotes)
  341. {
  342.   long count;
  343.   /* printf(" Text\n");
  344.      print_any("     DocumentID:  ", record->DocumentID);
  345.      printf("     VersionNumber:  %d\n", record->VersionNumber);
  346.      */
  347.   for(count = 0; count < record->DocumentText->size; count++){
  348.     long ch = (unsigned char)record->DocumentText->bytes[count];
  349.     if (ch == 27) {    /* What is this in for? Tim */
  350.  
  351.         /* then we have an escape code */
  352.         /* if the next letter is '(' or ')', then ignore two letters */
  353.         if('(' == record->DocumentText->bytes[count + 1] ||
  354.         ')' == record->DocumentText->bytes[count + 1])
  355.         count += 1;             /* it is a term marker */
  356.         else count += 4;        /* it is a paragraph marker */
  357.     } else if (ch == '\n' || ch == '\r') {
  358.         PUTC('\n');
  359.     } else if ((ch=='\t') || isprint(ch)){
  360.         PUTC(ch);
  361.     } 
  362.   }
  363. } /* output text record */
  364.  
  365.  
  366.  
  367. /*    Format A Search response for the client        display_search_response
  368. **    ---------------------------------------
  369. */
  370. /* modified from tracy shen's version in wutil.c
  371.  * displays either a text record or a set of headlines.
  372.  */
  373. void
  374. display_search_response ARGS4(
  375.     HTStructured *,        target,
  376.     SearchResponseAPDU *,    response,
  377.     char *,            database,
  378.     char *,             keywords)
  379. {
  380.   WAISSearchResponse  *info;
  381.   long i, k;
  382.   
  383.   BOOL archie =  strstr(database, "archie")!=0;    /* Specical handling */
  384.   
  385.   if (TRACE) fprintf(stderr, "HTWAIS: Displaying search response\n");
  386.   sprintf(line,
  387.       "Index %s contains the following %d item%s relevant to '%s'.\n",
  388.      database,
  389.      (int)(response->NumberOfRecordsReturned),
  390.      response->NumberOfRecordsReturned ==1 ? "" : "s",
  391.      keywords);
  392.  
  393.   PUTS(line);
  394.   PUTS("The first figure for each entry is its relative score, ");
  395.   PUTS("the second the number of lines in the item.");
  396.   START(HTML_MENU);
  397.  
  398.   if ( response->DatabaseDiagnosticRecords != 0 ) {
  399.     info = (WAISSearchResponse *)response->DatabaseDiagnosticRecords;
  400.     i =0; 
  401.  
  402.     if (info->Diagnostics != NULL)
  403.       showDiags((HTStream*)target, info->Diagnostics);
  404.  
  405.     if ( info->DocHeaders != 0 ) {
  406.       for (k=0; info->DocHeaders[k] != 0; k++ ) {
  407.     WAISDocumentHeader* head = info->DocHeaders[k];
  408.     char * headline = trim_junk(head->Headline);
  409.     any * docid = head->DocumentID;
  410.     char * docname;            /* printable version of docid */
  411.     i++;
  412.  
  413. /*    Make a printable string out of the document id.
  414. */
  415.     if (TRACE) fprintf(stderr, 
  416.         "HTWAIS:  %2ld: Score: %4ld, lines:%4ld '%s'\n", 
  417.            i,
  418.            (long int)(info->DocHeaders[k]->Score),
  419.            (long int)(info->DocHeaders[k]->Lines),
  420.            headline);
  421.  
  422.     START(HTML_LI);
  423.     sprintf(line, "%4ld  %4ld  ",
  424.         head->Score,
  425.         head->Lines);
  426.     PUTS( line);
  427.  
  428.     if (archie) {
  429.         char * www_name = WWW_from_archie(headline);
  430.         if (www_name) {
  431.         HTStartAnchor(target, NULL, www_name);
  432.         PUTS(headline);
  433.         
  434.         END(HTML_A);
  435.         free(www_name);
  436.         } else {
  437.          PUTS(headline);
  438.          PUTS(" (bad file name)");
  439.         }
  440.     } else { /* Not archie */
  441.         docname =  WWW_from_WAIS(docid);
  442.         if (docname) {
  443.         char * dbname = HTEscape(database, URL_XPALPHAS);
  444.         sprintf(line, "%s/%s/%d/%s",        /* W3 address */
  445.                     dbname,
  446.             head->Types ? head->Types[0] : "TEXT",
  447.             (int)(head->DocumentLength),
  448.             docname);
  449.         HTStartAnchor(target, NULL, line);
  450.         PUTS(headline);
  451.         END(HTML_A);
  452.         free(dbname);
  453.         free(docname);
  454.         } else {
  455.          PUTS("(bad doc id)");
  456.         }
  457.       }
  458.       } /* next document header */
  459.     } /* if there were any document headers */
  460.     
  461.     if ( info->ShortHeaders != 0 ) {
  462.       k =0;
  463.       while (info->ShortHeaders[k] != 0 ) {
  464.     i++;
  465.     PUTS( "(Short Header record, can't display)");
  466.       }
  467.     }
  468.     if ( info->LongHeaders != 0 ) {
  469.       k =0;
  470.       while (info->LongHeaders[k] != 0) {
  471.     i++;
  472.     PUTS( "\nLong Header record, can't display\n");
  473.       }
  474.     }
  475.     if ( info->Text != 0 ) {
  476.       k =0;
  477.       while (info->Text[k] != 0) {
  478.     i++;
  479.     PUTS( "\nText record\n");
  480.     output_text_record((HTStream*)target, info->Text[k++], false);
  481.       }
  482.     }
  483.     if ( info->Headlines != 0 ) {
  484.       k =0;
  485.       while (info->Headlines[k] != 0) {
  486.     i++;
  487.     PUTS( "\nHeadline record, can't display\n");
  488.     /* dsply_headline_record( info->Headlines[k++]); */
  489.       }
  490.     }
  491.     if ( info->Codes != 0 ) {
  492.       k =0;
  493.       while (info->Codes[k] != 0) {
  494.     i++;
  495.     PUTS( "\nCode record, can't display\n");
  496.     /* dsply_code_record( info->Codes[k++]); */
  497.       }
  498.     }
  499.   }                /* Loop: display user info */
  500.   END(HTML_MENU);
  501.   PUTC('\n'); ;
  502. }
  503.  
  504.  
  505.  
  506.  
  507. /*        Load by name                    HTLoadWAIS
  508. **        ============
  509. **
  510. **    This renders any object or search as required
  511. */
  512. PUBLIC int HTLoadWAIS ARGS4(
  513.     CONST char *,        arg,
  514.     HTParentAnchor *,    anAnchor,
  515.     HTFormat,        format_out,
  516.     HTStream*,        sink)
  517.  
  518. #define MAX_KEYWORDS_LENGTH 1000
  519. #define MAX_SERVER_LENGTH 1000
  520. #define MAX_DATABASE_LENGTH 1000
  521. #define MAX_SERVICE_LENGTH 1000
  522. #define MAXDOCS 40
  523.  
  524. {
  525.     static CONST char * error_header =
  526. "<h1>Access error</h1>\nThe following error occured in accesing a WAIS server:<P>\n";
  527.     char * key;              /* pointer to keywords in URL */
  528.     char* request_message = NULL; /* arbitrary message limit */
  529.     char* response_message = NULL; /* arbitrary message limit */
  530.     long request_buffer_length;    /* how of the request is left */
  531.     SearchResponseAPDU  *retrieval_response = 0;
  532.     char keywords[MAX_KEYWORDS_LENGTH + 1];
  533.     char *server_name;    
  534.     char *wais_database = NULL;        /* name of current database */
  535.     char *www_database;            /* Same name escaped */
  536.     char *service;
  537.     char *doctype;
  538.     char *doclength;
  539.     long document_length;
  540.     char *docname;
  541.     FILE *connection = 0;
  542.     char * names;        /* Copy of arg to be hacked up */
  543.     BOOL ok = NO;
  544.     
  545.     extern FILE * connect_to_server();
  546.     
  547.     if (!acceptable_inited) init_acceptable();
  548.     
  549.         
  550. /*    Decipher and check syntax of WWW address:
  551. **    ----------------------------------------
  552. **
  553. **    First we remove the "wais:" if it was spcified.  920110
  554. */  
  555.     names = HTParse(arg, "", PARSE_HOST | PARSE_PATH | PARSE_PUNCTUATION);
  556.     key = strchr(names, '?');
  557.     
  558.     if (key) {
  559.         char * p;
  560.     *key++ = 0;    /* Split off keywords */
  561.     for (p=key; *p; p++) if (*p == '+') *p = ' ';
  562.     HTUnEscape(key);
  563.     }
  564.     if (names[0]== '/') {
  565.     server_name = names+1;
  566.     if (as_gate =(*server_name == '/'))
  567.         server_name++;    /* Accept one or two */
  568.     www_database = strchr(server_name,'/');
  569.     if (www_database) {
  570.         *www_database++ = 0;        /* Separate database name */
  571.         doctype = strchr(www_database, '/');
  572.         if (key) ok = YES;    /* Don't need doc details */
  573.         else if (doctype) {    /* If not search parse doc details */
  574.         *doctype++ = 0;    /* Separate rest of doc address */
  575.         doclength = strchr(doctype, '/');
  576.         if(doclength) {
  577.             *doclength++ = 0;
  578.             document_length = atol(doclength);
  579.             if (document_length) {
  580.             docname=strchr(doclength, '/');
  581.             if (docname) {
  582.                 *docname++ = 0;
  583.                 ok = YES;    /* To avoid a goto! */
  584.             } /* if docname */
  585.             } /* if document_length valid */
  586.         } /* if doclength */
  587.         } else { /* no doctype?  Assume index required */
  588.             if (!key) key = "";
  589.         ok = YES;
  590.         } /* if doctype */
  591.     } /* if database */
  592.      }
  593.      
  594.      if (!ok)
  595.      return HTLoadError(sink, 500, "Syntax error in WAIS URL");
  596.  
  597.      if (TRACE) fprintf(stderr, "HTWAIS: Parsed OK\n");
  598.      
  599.      service = strchr(names, ':');
  600.      if (service)  *service++ = 0;
  601.      else service = "210";
  602.      
  603.      if (server_name[0] == 0)
  604.         connection = NULL;
  605.  
  606.      else if (!(key && !*key))
  607.       if ((connection=connect_to_server(server_name,atoi(service)))
  608.            == NULL)  {
  609.      if (TRACE) fprintf (stderr,
  610.          "%sCan't open connection to %s via service %s.\n",
  611.          error_header, server_name, service);
  612.      free(names);
  613.      return HTLoadError(sink, 500, "Can't open connection to WAIS server");
  614.     }
  615.  
  616.     StrAllocCopy(wais_database,www_database);
  617.     HTUnEscape(wais_database);
  618.     
  619.     /* This below fixed size stuff is terrible */
  620.     request_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
  621.     response_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
  622.  
  623. /*    If keyword search is performed but there are no keywords,
  624. **    the user has followed a link to the index itself. It would be
  625. **    appropriate at this point to send him the .SRC file - how?
  626. */
  627.  
  628.     if (key && !*key) {                /* I N D E X */
  629.     
  630. #ifdef CACHE_FILE_PREFIX
  631.     char filename[256];
  632.     FILE * fp;
  633. #endif
  634.     HTStructured * target = HTML_new(anAnchor, format_out, sink);
  635.     
  636.     START(HTML_ISINDEX);
  637.  
  638.     {
  639.         START(HTML_TITLE);
  640.         PUTS(wais_database);
  641.         PUTS(" index");
  642.         END(HTML_TITLE);
  643.         
  644.         START(HTML_H1);
  645.         PUTS(wais_database);
  646.         END(HTML_H1);
  647.         
  648.     }
  649.     /* If we have seen a source file for this database, use that:
  650.     */
  651.  
  652. #ifdef CACHE_FILE_PREFIX
  653.     sprintf(filename, "%sWSRC-%s:%s:%.100s.txt",
  654.         CACHE_FILE_PREFIX,
  655.         server_name, service, www_database);
  656.  
  657.     fp = fopen(filename, "r");    /* Have we found this already? */
  658.     if (TRACE) fprintf(stderr,
  659.         "HTWAIS: Description of server %s %s.\n",
  660.         filename,
  661.         fp ? "exists already" : "does NOT exist!");
  662.  
  663.     if (fp) {
  664.         char c;
  665.         START(HTML_PRE);        /* Preformatted description */
  666.         while((c=getc(fp))!=EOF) PUTC(c);    /* Transfer file */
  667.         END(HTML_PRE);
  668.         fclose(fp);
  669.     }
  670. #endif
  671.     START(HTML_P);
  672.     PUTS("Specify search words.");
  673.     
  674.     END_TARGET;
  675.     FREE_TARGET;
  676.     
  677.     } else if (key) {                    /* S E A R C H */
  678.     char *p;
  679.     HTStructured * target;
  680.     
  681.     strncpy(keywords, key, MAX_KEYWORDS_LENGTH);
  682.     while(p=strchr(keywords, '+')) *p = ' ';
  683.     
  684.         /* Send advance title to get something fast to the other end */
  685.     
  686.     target = HTML_new(anAnchor, format_out, sink);
  687.     
  688.     START(HTML_ISINDEX);
  689.     START(HTML_TITLE);
  690.     PUTS(keywords);
  691.     PUTS(" (in ");
  692.     PUTS(wais_database);
  693.     PUTS(")");
  694.     END(HTML_TITLE);
  695.     
  696.     START(HTML_H1);
  697.     PUTS(keywords);
  698.     END(HTML_H1);
  699.  
  700.     request_buffer_length = MAX_MESSAGE_LEN; /* Amount left */
  701.     if (TRACE) fprintf(stderr, "HTWAIS: Search for `%s' in `%s'\n",
  702.         keywords, wais_database);
  703.     if(NULL ==
  704.     generate_search_apdu(request_message + HEADER_LENGTH, 
  705.                 &request_buffer_length, 
  706.                 keywords, wais_database, NULL, MAXDOCS))
  707.     panic("request too large");
  708.     
  709.  
  710.     if(!interpret_message(request_message, 
  711.                 MAX_MESSAGE_LEN - request_buffer_length, 
  712.                 response_message,
  713.                 MAX_MESSAGE_LEN,
  714.                 connection,
  715.                 false    /* true verbose */
  716.                 )) {
  717.         panic("returned message too large");
  718.     
  719.         } else {    /* returned message ok */
  720.     
  721.         SearchResponseAPDU  *query_response = 0;
  722.         readSearchResponseAPDU(&query_response,
  723.             response_message + HEADER_LENGTH);
  724.         display_search_response(target, 
  725.             query_response, wais_database, keywords);
  726.         if (query_response->DatabaseDiagnosticRecords)
  727.         freeWAISSearchResponse(
  728.             query_response->DatabaseDiagnosticRecords);         
  729.         freeSearchResponseAPDU( query_response);
  730.     }    /* returned message not too large */
  731.     
  732.     END_TARGET;
  733.     FREE_TARGET;
  734.  
  735.     } else {            /* D O C U M E N T    F E T C H */
  736.     
  737.     HTFormat format_in;
  738.     HTStream * target;
  739.     long count;
  740.     any   doc_chunk;
  741.     any * docid = &doc_chunk;
  742.     if (TRACE) printf(
  743.         "HTWAIS: Retrieve document id `%s' type `%s' length %ld\n",
  744.         docname, doctype, document_length);
  745.         
  746.     format_in = 
  747.       !strcmp(doctype, "WSRC") ? HTAtom_for("application/x-wais-source") :
  748.       !strcmp(doctype, "TEXT") ? HTAtom_for("text/plain") :
  749.       !strcmp(doctype, "GIF")  ? HTAtom_for("image/gif") :
  750.                             HTAtom_for("text/plain");
  751.  
  752.     target = HTStreamStack(format_in, format_out, sink, anAnchor);
  753.     if (!target) return HTLoadError(sink, 500,
  754.         "Can't convert format of WAIS document");
  755. /*    Decode hex or litteral format for document ID
  756. */    
  757.     WAIS_from_WWW(docid, docname);
  758.  
  759.     
  760. /*    Loop over slices of the document
  761. */    
  762.     for(count = 0; 
  763.         count * CHARS_PER_PAGE < document_length;
  764.         count++){
  765.       char *type = s_strdup(doctype);    /* Gets freed I guess */
  766.       request_buffer_length = MAX_MESSAGE_LEN; /* Amount left */
  767.       if (TRACE) fprintf(stderr, "HTWAIS: Slice number %ld\n", count);
  768.       if(0 ==
  769.           generate_retrieval_apdu(request_message + HEADER_LENGTH,
  770.             &request_buffer_length, 
  771.             docid, 
  772.             CT_byte,
  773.             count * CHARS_PER_PAGE,
  774.             MIN((count + 1) * CHARS_PER_PAGE,document_length),
  775.             type,
  776.             wais_database
  777.             ))
  778.         panic("request too long");
  779.       
  780.       /*    Actually do the transaction given by request_message */   
  781.       if(0 ==
  782.          interpret_message(request_message, 
  783.                    MAX_MESSAGE_LEN - request_buffer_length, 
  784.                    response_message,
  785.                    MAX_MESSAGE_LEN,
  786.                    connection,
  787.                    false /* true verbose */    
  788.                    ))
  789.         panic("Returned message too large");
  790.  
  791.       /*     Parse the result which came back into memory.
  792.       */
  793.       readSearchResponseAPDU(&retrieval_response, 
  794.                  response_message + HEADER_LENGTH);
  795.  
  796.       if(NULL == ((WAISSearchResponse *)
  797.           retrieval_response->DatabaseDiagnosticRecords)->Text){
  798.         /* display_search_response(target, retrieval_response,
  799.                     wais_database, keywords); */
  800.         PUTS("No text was returned!\n");
  801.         /* panic("No text was returned"); */
  802.       } else {
  803.       
  804.         output_text_record(target,
  805.            ((WAISSearchResponse *)
  806.             retrieval_response->DatabaseDiagnosticRecords)->Text[0],
  807.         false);
  808.       
  809.       } /* If text existed */
  810.       
  811.     }    /* Loop over slices */
  812.  
  813.     (*target->isa->end_document)(target);
  814.     (*target->isa->free)(target);
  815.  
  816.     free (docid->bytes);
  817.     
  818.     freeWAISSearchResponse( retrieval_response->DatabaseDiagnosticRecords); 
  819.     freeSearchResponseAPDU( retrieval_response);
  820.  
  821.     } /* If document rather than search */
  822.  
  823.  
  824.  
  825.  
  826. /*    (This postponed until later,  after a timeout:)
  827. */
  828.     if (connection) close_connection(connection);
  829.     if (wais_database) free(wais_database);
  830.     s_free(request_message);
  831.     s_free(response_message);
  832.  
  833.     free(names);
  834.     return HT_LOADED;
  835. }
  836.  
  837. PUBLIC HTProtocol HTWAIS = { "wais", HTLoadWAIS, NULL };
  838.  
  839.  
  840.